package org.basic.mail.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.mail.MailAccount;
import cn.hutool.extra.mail.MailUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import org.apache.commons.lang3.StringUtils;
import org.basic.common.core.exception.ServiceException;
import org.basic.common.core.utils.MapstructUtils;
import org.basic.common.mybatis.core.page.TableDataInfo;
import org.basic.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;

import org.basic.mail.domain.SysMailAccount;
import org.basic.mail.domain.SysMailTemplate;
import org.basic.mail.domain.bo.SysMailLogBo;
import org.basic.mail.domain.bo.SysMailTemplateBo;
import org.basic.mail.domain.bo.SysMailTemplateDialogBo;
import org.basic.mail.domain.vo.MailTemplateRespVo;
import org.basic.mail.domain.vo.MailTemplateSendReqVo;
import org.basic.mail.domain.vo.SysMailTemplateVo;
import org.basic.mail.enums.MailSSL;
import org.basic.mail.mapper.SysMailTemplateMapper;
import org.basic.mail.service.ISysMailAccountService;
import org.basic.mail.service.ISysMailLogService;
import org.basic.mail.service.ISysMailTemplateService;
import org.basic.system.service.ISysConfigService;
import org.springframework.stereotype.Service;


import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.regex.Pattern;

/**
 * 邮件模版Service业务层处理
 *
 * @author Shao Hua
 * @date 2023-07-27
 */
@RequiredArgsConstructor
@Service
public class SysMailTemplateServiceImpl implements ISysMailTemplateService {

    /**
     * 正则表达式，匹配 {} 中的变量
     */
    private static final Pattern PATTERN_PARAMS = Pattern.compile("\\{(.*?)}");


    private final SysMailTemplateMapper baseMapper;

    private final ISysMailAccountService sysMailAccountService;

    private final ISysMailLogService sysMailLogService;

    private final ISysConfigService sysConfigService;
    /**
     * 查询邮件模版
     */
    @Override
    public MailTemplateRespVo queryById(Long id) {
        SysMailTemplate sysMailTemplate = baseMapper.selectById(id);
        String mailParams = sysMailTemplate.getMailParams();
        List<String> mailParamsList = JSONUtil.parseArray(mailParams).toList(String.class);
        MailTemplateRespVo mailTemplateRespVO = new MailTemplateRespVo();
        BeanUtil.copyProperties(sysMailTemplate, mailTemplateRespVO);
        mailTemplateRespVO.setMailParams(mailParamsList);
        return mailTemplateRespVO;
    }

    /**
     * 查询邮件模版列表
     */
    @Override
    public TableDataInfo<SysMailTemplateVo> queryPageList(SysMailTemplateBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<SysMailTemplate> lqw = buildQueryWrapper(bo);
        Page<SysMailTemplateVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询邮件模版列表
     */
    @Override
    public List<SysMailTemplateVo> queryList(SysMailTemplateBo bo) {
        LambdaQueryWrapper<SysMailTemplate> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<SysMailTemplate> buildQueryWrapper(SysMailTemplateBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<SysMailTemplate> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getName()), SysMailTemplate::getName, bo.getName());
        lqw.like(StringUtils.isNotBlank(bo.getCode()), SysMailTemplate::getCode, bo.getCode());
        lqw.eq(bo.getAccountId() != null, SysMailTemplate::getAccountId, bo.getAccountId());
        lqw.eq(bo.getStatus() != null, SysMailTemplate::getStatus, bo.getStatus());
        lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
            SysMailTemplate::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
        return lqw;
    }

    /**
     * 新增邮件模版
     */
    @Override
    public Boolean insertByBo(SysMailTemplateDialogBo bo) {
        SysMailTemplate add = MapstructUtils.convert(bo, SysMailTemplate.class);
        validEntityBeforeSave(add);
        List<String> paramsList = parseTemplateContentParams(bo.getContent());
        add.setMailParams(jsonListToString(paramsList));
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改邮件模版
     */
    @Override
    public Boolean updateByBo(SysMailTemplateDialogBo bo) {
        SysMailTemplate update = MapstructUtils.convert(bo, SysMailTemplate.class);
        validEntityBeforeSave(update);
        List<String> paramsList = parseTemplateContentParams(bo.getContent());
        update.setMailParams(jsonListToString(paramsList));
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(SysMailTemplate entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除邮件模版
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    /**
     * 发送邮件
     *
     * @param sendReqVO
     */
    @Override
    public String sendMail(MailTemplateSendReqVo sendReqVO) {
        String sendToMail = sendReqVO.getMail();
        Long templateId = sendReqVO.getId();
        Map<String, Object> templateParams = sendReqVO.getTemplateParams();
        MailTemplateRespVo mailTemplate = this.queryById(templateId);
        String title = mailTemplate.getTitle();
        String templateContent = mailTemplate.getContent();
        String content = formatMailTemplateContent(templateContent, templateParams);
        Long accountId = mailTemplate.getAccountId();
        SysMailAccount sysMailAccount = sysMailAccountService.queryByIdToSend(accountId);
        MailAccount hutoolMailAccount = toHutoolMailAccount(sysMailAccount);
        try {
            String send = MailUtil.send(hutoolMailAccount, sendToMail, title, content, true);
            System.out.println("记录发送成功日志");
            createSuccessMailLog(hutoolMailAccount, sendReqVO, mailTemplate, accountId, content, send);
            return sysConfigService.selectConfigByKey("mailSuccessMsg");
        } catch (Exception e) {
            System.out.println("记录发送失败日志");
            createLoseMailLog(hutoolMailAccount, sendReqVO, mailTemplate, accountId, content, e.getMessage());
            System.out.println("发送邮件异常:" + e.getMessage());
            String mailErrorMsg = sysConfigService.selectConfigByKey("mailErrorMsg");
            throw new ServiceException(mailErrorMsg);
        }
    }

    public List<String> parseTemplateContentParams(String content) {
        return ReUtil.findAllGroup1(PATTERN_PARAMS, content);
    }

    /**
     * json集合转String
     *
     * @param list
     * @return
     */
    public String jsonListToString(List<String> list) {
        JSONArray array = new JSONArray();
        array.addAll(list);
        //转为JSONArray字符串
        return array.toString();
    }

    /**
     * 邮件模版内容合成
     *
     * @param content 邮件模版
     * @param params  合成参数
     * @return 格式化后的内容
     */
    @Override
    public String formatMailTemplateContent(String content, Map<String, Object> params) {
        return StrUtil.format(content, params);
    }

    public MailAccount toHutoolMailAccount(SysMailAccount sysMailAccount) {
        MailAccount mailAccount = new MailAccount();
        mailAccount.setHost(sysMailAccount.getHost());
        mailAccount.setPort(sysMailAccount.getPort().intValue());
        mailAccount.setUser(sysMailAccount.getUsername());
        mailAccount.setPass(sysMailAccount.getPassword());
        mailAccount.setFrom(sysMailAccount.getMail());
        Integer sslEnable = sysMailAccount.getSslEnable();
        mailAccount.setSslEnable(MailSSL.getStatus(sslEnable));
        mailAccount.setStarttlsEnable(true);
        mailAccount.setTimeout(2000);
        mailAccount.setConnectionTimeout(2000);
        return mailAccount;
    }

    /**
     * 创建发送成功的消息日志
     *
     * @param mailAccount
     * @param sendReqVO
     * @param mailTemplate
     * @param accountId
     * @param content
     * @param send
     * @return
     */
    public Boolean createSuccessMailLog(MailAccount mailAccount, MailTemplateSendReqVo sendReqVO,
                                        MailTemplateRespVo mailTemplate, Long accountId, String content, String send) {
        SysMailLogBo sysMailLogBo = new SysMailLogBo();
        sysMailLogBo.setToMail(sendReqVO.getMail());
        sysMailLogBo.setAccountId(accountId);
        sysMailLogBo.setFromMail(mailAccount.getFrom());
        sysMailLogBo.setTemplateId(sendReqVO.getId());
        sysMailLogBo.setTemplateCode(sendReqVO.getTemplateCode());
        sysMailLogBo.setTemplateNickname(mailTemplate.getNickname());
        sysMailLogBo.setTemplateTitle(mailTemplate.getTitle());
        sysMailLogBo.setTemplateContent(content);
        sysMailLogBo.setTemplateParams(JSONUtil.toJsonStr(sendReqVO.getTemplateParams()));
        sysMailLogBo.setSendStatus(10L);
        sysMailLogBo.setSendTime(DateUtil.date());
        sysMailLogBo.setSendMessageId(send);
        return sysMailLogService.insertByBo(sysMailLogBo);

    }

    /**
     * 创建发送成功的消息日志
     *
     * @param mailAccount
     * @param sendReqVO
     * @param mailTemplate
     * @param accountId
     * @param content
     * @param send
     * @return
     */
    public Boolean createLoseMailLog(MailAccount mailAccount, MailTemplateSendReqVo sendReqVO,
                                     MailTemplateRespVo mailTemplate, Long accountId, String content, String send) {
        SysMailLogBo sysMailLogBo = new SysMailLogBo();
        sysMailLogBo.setToMail(sendReqVO.getMail());
        sysMailLogBo.setAccountId(accountId);
        sysMailLogBo.setFromMail(mailAccount.getFrom());
        sysMailLogBo.setTemplateId(sendReqVO.getId());
        sysMailLogBo.setTemplateCode(sendReqVO.getTemplateCode());
        sysMailLogBo.setTemplateNickname(mailTemplate.getNickname());
        sysMailLogBo.setTemplateTitle(mailTemplate.getTitle());
        sysMailLogBo.setTemplateContent(content);
        sysMailLogBo.setTemplateParams(JSONUtil.toJsonStr(sendReqVO.getTemplateParams()));
        sysMailLogBo.setSendStatus(20L);
        sysMailLogBo.setSendTime(DateUtil.date());
        sysMailLogBo.setSendException(send);
        return sysMailLogService.insertByBo(sysMailLogBo);

    }

    /**
     * 校验该邮箱是否需要开启 Starttls
     *
     * @param email
     * @return
     */
    public boolean validateStarttlsEnable(String email) {
        int index = email.indexOf("@");
        String domain = null;
        if (index != -1) {
            domain = StrUtil.subSuf(email, index + 1);
        }
        if ("outlook.com".equals(domain)) {
            return true;
        } else {
            return false;
        }
    }
}
